﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Data;
using System.Collections;

namespace PhantomMvvmToolkit.Converter
{
    /// <summary>
    /// This will convert a boolean value, numeric value, or a string value that can convert to a float.  It will also accept any of those types as nullable
    /// </summary> 
    /// <remarks>
    /// bool: true = 1, false = 0
    /// int, float, double: max of 1 and a min of 0
    /// string: "" are 0 otherwise it will float.TryParse for a value
    /// IEnumurator
    /// null: always 0
    /// Default: 1 if not a convertable type (one way)
    /// 
    /// Adding a parameter of "Inverse" will cause all results to be reversed
    /// </remarks>
    /// <exception cref="InvalidOperationException"></exception>
    public class ToOpacity : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var inverse = false;
            float result = 0;

            if (parameter != null && parameter.ToString().ToLower() == "inverse")
            {
                inverse = true;
            }

            if (value is bool)
            {
                result = (bool)value ? (float)1 : (float)0;
            }
            else if (value is int)
            {
                result = (int)value == 0 ? (float)0 : (float)1;
            }
            else if (value is float)
            {
                var current = (float)value;
                result = current < (float)0 ? (float)0 :
                         current > (float)1 ? (float)1 :
                         current;
            }
            else if (value is double)
            {
                var current = (float)((double)value);
                result = current < 0 ? 0 :
                         current > 1 ? 1 :
                         current;
            }
            else if (value is string)
            {
                if (string.IsNullOrEmpty((string)value))
                    result = 0;

                float floatOut;

                if (float.TryParse((string)value, out floatOut))
                {
                    result = floatOut < 0 ? 0 :
                             floatOut > 1 ? 1 :
                             floatOut;
                }
                else
                {
                    throw new InvalidOperationException(string.Format("Type is string but it did not convert to a valid flaot value.  It's value was {0}", value));
                }
            }
            else if (value == null)
            {
                result = 0;
            }
            else
            {
                result = 1;
            }

            if (inverse)
                return 1 - result;
            else
                return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var current = (float)value;

            if (parameter.ToString().ToLower() == "inverse")
            {
                current = 1 - current;
            }

            if (targetType == typeof(bool) || targetType == typeof(bool?))
            {
                return current == 1;
            }

            if (targetType == typeof(int) || targetType == typeof(int?))
            {
                return (float)current;
            }

            if (targetType == typeof(float) || targetType == typeof(double) || 
                targetType == typeof(float?) || targetType == typeof(double?))
            {
                return current;
            }

            if (targetType == typeof(string))
            {
                return current.ToString();
            }

            throw new InvalidOperationException(string.Format("Type {0} is not a valid conversion type.", targetType.Name));
        }
    }
}
